package stud.mpgame.old;

import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.logging.LoggingFilter;
import stud.mpgame.network.Message;
import stud.mpgame.network.NetworkMonitor;
import stud.mpgame.network.TCPNetworkMonitor;
import stud.mpgame.network.util.MessageFilter;
import stud.mpgame.old.game.GameCommandDescription;
import stud.mpgame.old.game.GameProtocolHandler;
import stud.mpgame.old.game.GameWorld;
import stud.mpgame.old.game.GameWorldDescription;
import stud.mpgame.snapshot.SnapshotManager;

import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {

    private static final int SNAPSHOT_MANAGER_TICK_TIME = 25;
    private static final int SNAPSHOT_MANAGER_SNAPSHOT_LENGTH = 20;
    private static final int SNAPSHOT_MANAGER_INITIAL_POSITION = 10;

    private NetworkMonitor networkMonitor;
    private SnapshotManager snapshotManager;
    private final int protocolVersion = 1;
    private GameWorld gameWorld;
    private long startAppTime;
    private GameProtocolHandler gameProtocolHandler;
    private static final String defaultConfig = "server/server.properties";

    private Main() throws Exception {
        startAppTime = System.currentTimeMillis();
        networkMonitor = new TCPNetworkMonitor(startAppTime, protocolVersion);
        gameWorld = new GameWorld(networkMonitor.nowTime(), networkMonitor);
        snapshotManager = new SnapshotManager(SNAPSHOT_MANAGER_TICK_TIME, SNAPSHOT_MANAGER_SNAPSHOT_LENGTH);
    }

    private void initializationServer(String path) throws Exception {
        ServerConfiguration.getInstance().initialization(path);
    }

    public static void main(String[] args) throws Exception {
        Main main = new Main();
        main.initializationServer(args.length > 0 ? args[0] : defaultConfig);
        main.bind();
        main.start();
    }

    private void bind() throws Exception {
        gameProtocolHandler = new GameProtocolHandler(networkMonitor, snapshotManager);

        snapshotManager.setInitialSnapshot(gameWorld, SNAPSHOT_MANAGER_INITIAL_POSITION);

        MessageFilter messageFilter = new MessageFilter(GameCommandDescription.getInstance());
        networkMonitor.getMessageDispatcher().addMessageReceivedListener(messageFilter, gameWorld);

        networkMonitor.bind();
    }

    private void start() throws Exception {

        int time;
        int nextUpdateTime = networkMonitor.nowTime();

        int delay = ServerConfiguration.getInstance().getDelay();

        //dummy cycle
        while(true) {
            time = networkMonitor.nowTime();
            if (time >= nextUpdateTime) {
                int dt = time - nextUpdateTime + delay;
                snapshotManager.update(dt);
                nextUpdateTime += delay;
                sendGameWorld();
            } else {
                try {
                    Thread.sleep(nextUpdateTime - time);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    private void sendGameWorld() {
        for(IoSession session : gameProtocolHandler.getSessions()) {
            Message message = new Message(session, GameWorldDescription.getInstance());
            GameWorld snapshot = (GameWorld) snapshotManager.getSnapshot(networkMonitor.nowTime());
            message.putUserObject(snapshot);
            message.send();
        }
    }

}